package com.ts.opengl.simpleDraw

import android.content.Context
import android.graphics.BitmapFactory
import android.opengl.ETC1Util.loadTexture
import android.opengl.GLES20
import android.opengl.GLES20.GL_ARRAY_BUFFER
import android.opengl.GLES20.GL_ELEMENT_ARRAY_BUFFER
import android.opengl.GLES20.GL_FALSE
import android.opengl.GLES20.GL_FLOAT
import android.opengl.GLES20.GL_LINEAR
import android.opengl.GLES20.GL_LINEAR_MIPMAP_LINEAR
import android.opengl.GLES20.GL_NEAREST
import android.opengl.GLES20.GL_STATIC_DRAW
import android.opengl.GLES20.GL_TEXTURE0
import android.opengl.GLES20.GL_TEXTURE1
import android.opengl.GLES20.GL_TEXTURE_2D
import android.opengl.GLES20.GL_TEXTURE_MAG_FILTER
import android.opengl.GLES20.GL_TEXTURE_MIN_FILTER
import android.opengl.GLES20.glActiveTexture
import android.opengl.GLES20.glBindBuffer
import android.opengl.GLES20.glBindTexture
import android.opengl.GLES20.glBufferData
import android.opengl.GLES20.glDeleteTextures
import android.opengl.GLES20.glEnableVertexAttribArray
import android.opengl.GLES20.glGenBuffers
import android.opengl.GLES20.glGenTextures
import android.opengl.GLES20.glGenerateMipmap
import android.opengl.GLES20.glGetError
import android.opengl.GLES20.glGetUniformLocation
import android.opengl.GLES20.glTexParameteri
import android.opengl.GLES20.glUniform1i
import android.opengl.GLES20.glUniformMatrix4fv
import android.opengl.GLES20.glUseProgram
import android.opengl.GLES20.glVertexAttribPointer
import android.opengl.GLES20.glViewport
import android.opengl.GLES30
import android.opengl.GLES30.glBindVertexArray
import android.opengl.GLES30.glGenVertexArrays
import android.opengl.GLSurfaceView
import android.opengl.GLUtils
import android.opengl.Matrix
import android.util.Log
import com.ts.audiocamera.R
import java.nio.IntBuffer
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.opengles.GL10
import kotlin.math.sin


class transformRender(var context: Context): GLSurfaceView.Renderer {

    var ver= floatArrayOf(
        // positions         //color              // texture coords
        -1.0f,  1.0f, 0.0f,   1.0f, 0.0f, 0.0f,    1.0f, 0.0f, // top right
        -1.0f, -1.0f, 0.0f,   1.0f, 0.0f, 1.0f,   1.0f, 1.0f, // bottom right
        1.0f, 1.0f, 0.0f,   1.0f, 0.0f, 1.0f,   0.0f,0.0f, // bottom left
        1.0f,  -1.0f, 0.0f,   0.0f, 0.5f, 1.0f,   0.0f, 1.0f, // top left
    )

    var ele1= intArrayOf(
        0, 1, 2,
        1, 2, 3
    )

    fun logMatrix( result:FloatArray,TAG1:String="矩阵"){
        var conte=""
        result.forEachIndexed { index, fl ->
            if ((index+1)/4==0){
                conte="\n"
            }
            conte+=result.get(index).toString()+" "


        }
        Log.e(TAG,TAG1+"矩阵:"+conte)
    }
    val vbo=IntArray(1)
    val vao=IntArray(1)
    val ebo=IntArray(1)

    val texture=IntArray(2)

    var program=0;
    lateinit var ele: IntBuffer
    private  val TAG = "transformRender"
    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {

        program=openglUtil.createProgram(context, R.raw.transform_vert,R.raw.transform)

        val attribu=openglUtil.createFloatBuffer(ver);
        ele =openglUtil.createIntBuffer(ele1);
        //-----------------初始化
        glGenVertexArrays(1,vao,0)
        glGenBuffers(1,vbo,0)
        glBindVertexArray(vao[0])

        Log.e(TAG, glGetError().toString()+"---")
        glBindBuffer(GL_ARRAY_BUFFER,vbo[0])
        glBufferData(GL_ARRAY_BUFFER,
            attribu.capacity()*4,attribu,
            GL_STATIC_DRAW)
        Log.e(TAG, glGetError().toString()+"---")

        Log.e(TAG, glGetError().toString()+"---")
        glGenBuffers(ebo.size,ebo,0)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,ebo[0])
        glBufferData(GL_ELEMENT_ARRAY_BUFFER,ele.capacity()*4,
            ele, GL_STATIC_DRAW)
        Log.e(TAG, glGetError().toString()+"---")



        attribu.position(0)
        glVertexAttribPointer(0,3, GL_FLOAT,false,8*4,0)
        glEnableVertexAttribArray(0)

        Log.e(TAG, glGetError().toString()+"---")
        attribu.position(3)
        glVertexAttribPointer(1,3, GL_FLOAT,false,8*4,4*3)
        glEnableVertexAttribArray(1)

        Log.e(TAG, glGetError().toString()+"---")
        attribu.position(6)
        glVertexAttribPointer(2,2, GL_FLOAT,false,8*4,4*6)
        glEnableVertexAttribArray(2)

        texture[0]=loadTexture(context,R.drawable.hyw)
        texture[1]=loadTexture(context,R.drawable.cdemo)
        glBindBuffer(GL_ARRAY_BUFFER,0)
        glBindVertexArray(0)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0)
    }

    var rotateX=0.0f;

    var rotateY=0.0f;

    var scaleX=0.0f;

    var scaleY=0.0f;


    var newRotateX=0;
    var newRotateY=0

    var mscaleX=0f;
    var mscaleY=0f;
    var Projection=FloatArray(4*4){0.0f}
    var View=FloatArray(4*4){1.0f}
    var result=FloatArray(4*4){1.0f}
    var rotateX1:Float=0.0f;
    var rotateY1:Float=0.0f;
    var scaleX1:Float=0.0f;
    var scaleY1:Float=0.0f;

    fun setUpdateMVPMatrix1(rotateX:Float,  rotateY:Float,
    scaleX:Float,scaleY:Float){
        rotateX1=rotateX;
        rotateY1=rotateY;
        scaleX1=scaleX;
        scaleY1=scaleY;
    }

    fun setUpdateMVPMatrix(rotateX:Float,  rotateY:Float,
                           ratio:Float){
        Log.e(TAG, "$rotateX---$rotateY---$ratio--"
        )
        newRotateX=rotateX.toInt()%360
        newRotateY=rotateY.toInt()%360

        var radiansX=(Math.PI /180.0f * newRotateX).toFloat()

        var radiansY=(Math.PI /180.0f * newRotateY).toFloat()

       Matrix.perspectiveM(Projection,0,45f,ratio,0.1f,100.0f)
        result=Projection;

        logMatrix(View,"Projection")
        Matrix.setLookAtM(View,0,
            0.0f,0.0f,4.0f,// Camera is at (0,0,1), in World Space
                 0.0f,0.0f,0.0f,// and looks at the origin
            0.0f,1.0f,0.0f) // Head is up (set to 0,-1,0 to look upside-down)
        logMatrix(View,"View")
        val mode=FloatArray(4*4){1.0f}

        Matrix.scaleM(mode,0,scaleX1,scaleY1,1.0f)
        Matrix.rotateM(mode,0,radiansX,1.0f,0.0f,0.0f)
        Matrix.rotateM(mode,0,radiansY,0.0f,1.0f,0.0f)
        Matrix.translateM(mode,0,0.0f,0.0f,0.0f)
        logMatrix(View,"mode")
        Matrix.multiplyMM(result,0,Projection,0,View,0)
        Matrix.multiplyMM(result,0,result,0,mode,0)
        logMatrix(View,"result")
    }

    var width=0;
    var height=0;

    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
        this.width=width;
        this.height=height
        glViewport(0,0,width,height)

    }

    //  context用户解析纹理资源时使用，resourceId为纹理资源的ID
    fun loadTexture(context: Context, resourceId: Int): Int {
        //textureObjectIds用于存储OpenGL生成纹理对象的ID，我们只需要一个纹理
        val textureObjectIds = IntArray(1)
        //1代表生成一个纹理
        glGenTextures(1, textureObjectIds, 0)
        //判断是否生成成功
        if (textureObjectIds[0] == 0) {
            Log.w(TAG, "generate a texture object failed!")
            return 0
        }
        //加载纹理资源，解码成bitmap形式
        val options = BitmapFactory.Options()
        options.inScaled = false
        val bitmap = BitmapFactory.decodeResource(context.resources, resourceId, options)

        if (bitmap == null) {
            Log.w(TAG, "Resource ID: $resourceId decoded failed")
            //删除指定的纹理对象
            glDeleteTextures(1, textureObjectIds, 0)
            return 0
        }
        //第一个参数代表这是一个2D纹理，第二个参数就是OpenGL要绑定的纹理对象ID，也就是让OpenGL后面的纹理调用都使用此纹理对象
        glBindTexture(GL_TEXTURE_2D, textureObjectIds[0])
        //设置纹理过滤参数，GL_TEXTURE_MIN_FILTER代表纹理缩写的情况，GL_LINEAR_MIPMAP_LINEAR代表缩小时使用三线性过滤的方式，至于过滤方式以后再详解
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
        //GL_TEXTURE_MAG_FILTER代表纹理放大，GL_LINEAR代表双线性过滤
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        //加载实际纹理图像数据到OpenGL ES的纹理对象中，这个函数是Android封装好的，可以直接加载bitmap格式，
        GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0)
        //bitmap已经被加载到OpenGL了，所以bitmap可释放掉了，防止内存泄露
        bitmap.recycle()
        //我们为纹理生成MIP贴图，提高渲染性能，但是可占用较多的内存
        glGenerateMipmap(GL_TEXTURE_2D)
        //现在OpenGL已经完成了纹理的加载，不需要再绑定此纹理了，后面使用此纹理时通过纹理对象的ID即可
        glBindTexture(GL_TEXTURE_2D, 0)
        //返回OpenGL生成的纹理对象ID
        return textureObjectIds[0]
    }

    var count=0

    var sum=10
    override fun onDrawFrame(gl: GL10?) {
        Log.e(TAG,"onDrawFrame")

        glUseProgram(program)
//        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
        GLES30.glClearColor(1.0f,1.0f,1.0f,1.0f)
        glBindVertexArray(vao[0])

        if (count>=100){
            count=0;
        }

//        var time=System.currentTimeMillis().toInt();
//
//         var sim=sin(time.toDouble()).toFloat()
//        Log.e(TAG,"sin"+sin(sim))
        setUpdateMVPMatrix(rotateX1,rotateY1,width/height.toFloat())
        glUniform1i(glGetUniformLocation(program,"u_ScaleRatio"),count++)
        glUniformMatrix4fv(glGetUniformLocation(program, "u_MVPMatrix"), 1, false,result,0);
//         Log.e(TAG,"矩阵"+result.toString())
//        for (fl in result) {
//            Log.e(TAG,fl.toString()+"矩阵");
//        }
        logMatrix(result)

        glActiveTexture(GL_TEXTURE0);//先激活对应的纹理单元
        glBindTexture(GLES30.GL_TEXTURE_2D,texture[0])
        glUniform1i(glGetUniformLocation(program,"outTexture1"),0)

        glActiveTexture(GL_TEXTURE1)//先激活对应的纹理单元
        glBindTexture(GLES30.GL_TEXTURE_2D,texture[1])

        glUniform1i(glGetUniformLocation(program,"outTexture2"),1)

        GLES30.glDrawElements(GLES20.GL_TRIANGLE_STRIP,
            6, GLES20.GL_UNSIGNED_INT, 0)
        Log.e(TAG, glGetError().toString()+"---")

    }
}